package com.sinosoft.common.encrypt.utils;

import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.*;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.symmetric.SM4;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;

import java.nio.charset.StandardCharsets;

/**
 * 加密工具类，提供 SM2/SM4 加解密功能和签名计算
 */
@Slf4j
public class CryptoUtils {

    /**
     * 使用 SM2 私钥解密 SM4 密钥
     */
    public static String decryptSm4Key(String encryptedKey, String sm2PrivateKey) {
        if (encryptedKey == null || encryptedKey.isEmpty()) {
            throw new RuntimeException("加密密钥不能为空");
        }
        if (sm2PrivateKey == null || sm2PrivateKey.isEmpty()) {
            throw new RuntimeException("SM2私钥不能为空");
        }

        try {
            return SmUtil.sm2(sm2PrivateKey, null).decryptStr(encryptedKey, KeyType.PrivateKey);
        } catch (Exception e) {
            log.error("SM4密钥解密失败: {}", e.getMessage());
            throw new RuntimeException("SM4密钥解密失败: " + e.getMessage());
        }
    }

    /**
     * 使用 SM2 公钥加密 SM4 密钥
     */
    public static String encryptSm4Key(String sm4Key, String sm2PublicKey) {
        if (sm4Key == null || sm4Key.isEmpty()) {
            throw new RuntimeException("SM4密钥不能为空");
        }
        if (sm2PublicKey == null || sm2PublicKey.isEmpty()) {
            throw new RuntimeException("SM2公钥不能为空");
        }
        try {
            return SmUtil.sm2(null, sm2PublicKey).encryptHex(sm4Key, KeyType.PublicKey);
        } catch (Exception e) {
            log.error("SM4密钥加密失败: {}", e.getMessage());
            throw new RuntimeException("SM4密钥加密失败: " + e.getMessage());
        }
    }

    /**
     * 验证SM4密钥有效性
     */
    private static void validateSm4Key(String key) {
        if (key == null || key.isEmpty()) {
            throw new RuntimeException("SM4密钥不能为空");
        }
        if (key.length() != 32) {
            throw new RuntimeException("SM4密钥长度必须为32个十六进制字符");
        }
        try {
            HexUtil.decodeHex(key);
        } catch (Exception e) {
            throw new RuntimeException("SM4密钥必须是有效的十六进制字符串");
        }
    }

    /**
     * 使用 SM4 密钥解密请求体内容
     */
    public static String decryptBody(String encryptedBody, String sm4Key) {
        validateSm4Key(sm4Key);
        if (encryptedBody == null || encryptedBody.isEmpty()) {
            throw new RuntimeException("加密数据不能为空");
        }
        try {
            byte[] keyBytes = HexUtil.decodeHex(sm4Key);
            SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, keyBytes, keyBytes);
            return sm4.decryptStr(encryptedBody, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("SM4解密失败: {}", e.getMessage());
            throw new RuntimeException("解密处理失败: " + e.getMessage());
        }
    }

    /**
     * 使用 SM4 密钥加密报文内容
     */
    public static String encryptBody(String encryptedData, String sm4Key) {
        validateSm4Key(sm4Key);
        try {
            byte[] keyBytes = HexUtil.decodeHex(sm4Key);
            SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, keyBytes, keyBytes);
            return sm4.encryptHex(encryptedData, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("SM4加密失败: {}", e.getMessage());
            throw new RuntimeException("加密处理失败: " + e.getMessage());
        }
    }

    /**
     * 计算SM3哈希值
     */
    public static String calculateSm3(String content) {
        return SmUtil.sm3(content);
    }

    /**
     * 计算签名（先MD5再SM3）
     */
    public static String calculateSignature(String content) {
        String md5Hex = DigestUtil.md5Hex(content);
        return SmUtil.sm3(md5Hex);
    }

    /**
     * 生成SM2密钥对
     */
    public static void generateSm2KeyPair() {
        var sm2 = SmUtil.sm2();
        System.out.println("Private Key (Base64): " + sm2.getPrivateKeyBase64());
        System.out.println("Public Key (Base64): " + sm2.getPublicKeyBase64());
    }
} 